/**
 * 查询组件
 * by zhangxinyue
 * create 2020.08.19
 * modify 2021.09.01 适配1600，小于1920时三等分，大于等于1920时四等分，可支持放8个字
 * modify 2023.05.25 在此之前，组件根据屏幕分辨率自动进行布局。本次修改，增加了一种模式：根据父节点容器的宽度设置自适应的展示。
 *                   添加了parentId属性，当parentId为undefined时，按照原先屏幕自适应逻辑；当parentId不为undefined时，根据parentId获取父容器的宽度，进行自适应设置
 */
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Form } from '@ant-design/compatible';
import '@ant-design/compatible/assets/index.css';
import { Row, Col } from 'antd';
import _ from 'lodash';
import { DATA_ENTRY } from '../form';
import { PrimaryC, PrimaryGhostC } from '../button';
import FormItems from './formItems';
import style from './style.less';

/**
 * 按照屏幕自适应分辨率时：
 * 1 每一项最小宽度为312px
 * 2 一行最多4项
 * 3 当组件宽度小于4*312=1248px时，自动换行
 * 4 当组件宽度大于1248px时，展示4项，自动扩充
 *
 * 按照父容器自适应分辨率时：
 * 1 父容器宽度小于等于900，一排2个
 * 2 父容器宽度在900到1920之间，一排放3个
 * 3 父容器宽度大于1920，一排放4个
 */

class AdvancedSearch extends Component {
  // props默认值
  static defaultProps = {
    allowClear: true, // 默认显示“重置”按钮
    allowQuery: true, // 默认显示“查询”按钮
    allowMore: false, // 默认不支持“展开/收起”按钮
    dataSource: [], // 查询条件数据源
    moreData: [], // 当allowMore为true时，展开的查询条件
    onQuery: () => {}, // 点击“查询”时，向外抛出查询数据
    onClear: () => {}, // 点击“清除”时，抛出事件
    resultIncludeNull: false, // 默认在onQuery事件中将未设置条件移除
    queryDisabled: false, // 默认查询按钮不是disable状态
    buttonText: '查询', // 默认按钮文本是“查询”
    selfButt: undefined, // 默认无自定义按钮
    onRef: () => {}, // 本组件的引用
    parentId: undefined, // 当该组件不按照自适应的页面分辨率进行展示时，需要设置组件的父节点ID（每个引用需要设置不一样的Id），根据父节点的宽度进行布局设置
  };

  state = {
    fieldInRow: 4, // 默认一行展示四个元素
    query: {}, // 精确和模糊查询组件查询条件
  };

  componentDidMount() {
    // 父组件对本组件的引用
    this.props.onRef(this);
    // 添加窗口大小的监听
    window.addEventListener('resize', this.windowChange);
    this.windowChange();
  }
  componentWillUnmount() {
    // 删除窗口大小的监听
    window.removeEventListener('resize', this.windowChange);
  }

  // 根据分辨率判断是否需要title自动换行
  autoWrap = (titleLength, helper = false, required = false) => {
    if (!titleLength) return false;

    const screenWidth = document.documentElement.clientWidth;
    if (screenWidth < 1700 && titleLength > 11) return true;
    if (screenWidth >= 1700 && screenWidth < 1800 && titleLength > 12) return true;
    if (screenWidth >= 1800 && screenWidth < 1900 && titleLength > 13) return true;
    if (screenWidth >= 1900 && screenWidth < 1920 && titleLength > 13) return true;

    if (screenWidth >= 1920 && screenWidth < 2100 && titleLength > 9) return true;
    if (screenWidth >= 2100 && screenWidth < 2300 && titleLength > 10) return true;
    if (screenWidth >= 2300 && screenWidth < 2500 && titleLength > 11) return true;
    if (screenWidth >= 2500 && titleLength > 12) return true;
    if (helper) {
      if (screenWidth < 1320 && titleLength > 7 && required) return true;
      if (screenWidth < 1700 && titleLength > 8) return true;
      if (screenWidth >= 1700 && screenWidth < 1800 && titleLength > 8) return true;
      if (screenWidth >= 1800 && screenWidth < 1900 && titleLength > 9) return true;
      if (screenWidth >= 1900 && screenWidth < 1920 && titleLength > 10) return true;
      //表单中控制当目前是四行占一行的时候并且 带title 数字为8个长度的时候 1920的时候
      if (this.state.fieldInRow == 4) {
        if (screenWidth >= 1920 && screenWidth < 2100 && titleLength == 8 && !required) return true;
      } else {
        //以前的逻辑控制
        if (screenWidth >= 1920 && screenWidth < 2100 && titleLength == 8 && !required) return false;
      }
      if (screenWidth >= 1920 && screenWidth < 2100 && titleLength > 8) return true;
      if (screenWidth >= 2100 && screenWidth < 2300 && titleLength > 8) return true;
      if (screenWidth >= 2300 && screenWidth < 2500 && titleLength > 9) return true;
      if (screenWidth >= 2500 && screenWidth < 2600 && titleLength > 10) return true;
      if (screenWidth >= 2600 && titleLength > 11) return true;
    }
    return false;
  };

  // 窗口大小变更触发
  windowChange = () => {
    // 父组件传递了parentId，需要通过父容器的宽度来进行自适应适配
    if (this.props.parentId != undefined) {
      const formIdForWidthDom = document.querySelector(`#${this.props.parentId}`); // 获取父容器DOM元素
      const formIdForWidthDomClientWidth = formIdForWidthDom?.clientWidth; // 获取父容器的宽度

      // 父容器宽度小于等于900时，一排放2个元素
      if (formIdForWidthDomClientWidth <= 900) {
        this.setState({
          fieldInRow: 2,
        });
        return;
      }
      // 父容器宽度在900~1920之间，一排放3个元素
      if (formIdForWidthDomClientWidth < 1920 && formIdForWidthDomClientWidth > 900) {
        this.setState({
          fieldInRow: 3,
        });
        return;
      }
      // 父容器大于等于1920时，一排放4个元素
      if (formIdForWidthDomClientWidth >= 1920) {
        this.setState({
          fieldInRow: 4,
        });
      }
    } else {
      // 父组件未传递parentId时，按照屏幕分辨率，布局自适应

      const screenWidth = document.documentElement.clientWidth; // 获取屏幕宽度

      // 屏幕宽度小于1920时，一排放3个
      if (screenWidth < 1920) {
        if (this.state.fieldInRow !== 3) {
          this.setState({
            fieldInRow: 3,
          });
        }
        return;
      }
      // 屏幕宽度大于1920时，一排放4个
      if (screenWidth >= 1920) {
        if (this.state.fieldInRow !== 4) {
          this.setState({
            fieldInRow: 4,
          });
        }
      }
    }
  };

  /**
   * 生成查询条件
   * @param {*} numInRow 一行元素的个数
   */
  getFields(numInRow) {
    const { dataSource } = this.props;
    let resetData = []; // 当查询条件中包含DATA_ENTRY.SEARCHANDSELECTC（精确查询组件）元素时，存续触发精确查询时，要清空的元素ID
    const children = []; // 将DataSource中的值转变成DOM元素，存储在children中
    let placeholder = 1; // 记录接下来要从第几个占位开始（最终按钮的位置需要根据placeholder进行计算

    // 遍历数组，将数据转换成可展示的html
    dataSource.forEach((item, index) => {
      // title自动换行
      let autoWrap = this.autoWrap(item.title && item.title.length, !!item.helper, item.rules && item.rules.length && item.rules.find((item) => item.required));
      item.labalWrap = autoWrap;

      // 在系统管理中，类似于产品管理、自定义标的管理页面的查询条件，若选择了名称对应的下拉，则相当于触发了精确查询
      // 精确查询会将其他查询条件清空，并且不用点击查询按钮，直接触发查询
      // 所以resetData中存储的是除了SEARCHANDSELECTC组件外，其他组件的dataIndex，方便后面进行条件清空
      if (item.type != DATA_ENTRY.SEARCHANDSELECTC) {
        resetData.push(item.dataIndex);
      }

      // 根据嵌入的不同组件，进行布局
      switch (item.type) {
        case DATA_ENTRY.COMPLEXDATE: // 当组件类型为COMPLEXDATE（复杂的时间区间组件），需要特殊处理占位，占2位
        case DATA_ENTRY.HOlDDATERANGEC: // 当组件类型为HOLDDATERANGE（绩效分析的时间区间组件），需要特殊处理占位，占2位
        case DATA_ENTRY.PRODUCTGROUPSEP: // 当组件类型为产品+组合，需要特殊处理占位，占2位（目前在查询条件中没有引用该组件，若引用，还需要升级，需要特殊处理，因为组件包含的两个元素可以换行
          if (!item.hide) {
            children.push(
              <Col span={(24 / numInRow) * 2} key={index}>
                <FormItems {...item} form={this.props.form} />
              </Col>,
            );
            // 若下一个元素从当前行的第4位开始，由于该元素占2位，那么会空着当前行的最后一位，在第二行占前两位，那么就意味着该元素一共消耗掉3位
            if (placeholder % numInRow == 0) {
              placeholder += 3;
            } else {
              // 若下一个元素不是从当前行第4位开始，那么该元素正常消耗掉2位
              placeholder += 2;
            }
          }
          break;
        // 当组件类型为租户+部门，需要特殊处理占位，根据用户角色，占位不同.
        // 该组件没有被引用，与产品+组合类似，及时占2位，也跟其他占两位的组件不同，两个元素是可以换行的，后续如果需要可进行优化
        case DATA_ENTRY.TENANTDEPARTMENT:
          if (!item.hide) {
            if (localStorage.getItem('antd-pro-superMan') == 'true') {
              children.push(
                <Col span={(24 / numInRow) * 2} key={index}>
                  <FormItems {...item} form={this.props.form} />
                </Col>,
              );
              if (placeholder % numInRow == 0) {
                placeholder += 3;
              } else {
                placeholder += 2;
              }
            } else {
              children.push(
                <Col span={24 / numInRow} key={index}>
                  <FormItems {...item} form={this.props.form} />
                </Col>,
              );
              placeholder++;
            }
          }
          break;
        // 在系统管理中，类似于产品管理、自定义标的管理页面的查询条件，若选择了名称对应的下拉，则相当于触发了精确查询
        case DATA_ENTRY.SEARCHANDSELECTC:
          // dataIndex：组件ID
          // value: 组件选中值的ID
          item.onChange = (dataIndex, value) => {
            let query = {};
            // 这类组件的dataIndex会传入一个数组，长度为2，数组第一个元素是精确查询时对应的key值，第二个元素对应的是模糊查询时对应的key值
            // 以“产品管理”为例：第一个参数的为codeId，代表根据产品code精确查询；第二个参数为productName，代表根据产品名称进行模糊查询
            if (dataIndex == item.dataIndex[0]) {
              query[dataIndex] = value; // 构建精确查询的查询条件
              this.props.form.resetFields(resetData); // 精确查询时，清除其他查询条件
              this.props.onQuery(query); // 直接触发精确查询
            } else {
              query[dataIndex] = value; // 添加模糊查询的条件
            }
            this.setState({ query }); // 将查询条件存储到state中
          };
        default:
          // 正常情况下，一个元素占一行的四分之一,且没有额外的透传参数需要处理
          if (!item.hide) {
            children.push(
              <Col span={24 / numInRow} key={index}>
                <FormItems {...item} form={this.props.form} />
              </Col>,
            );
            placeholder++;
          }
      }
    });

    // 按钮
    if (numInRow === 4) {
      switch ((placeholder - 1) % 4) {
        case 0: // 元素占位为4、8、12...，按钮另起一行，放在行末
          children.push(
            <Col span={24} key={new Date().getTime() + Math.random()}>
              <div style={{ width: (94 / 96) * 100 + '%', display: 'flex', flexDirection: 'row-reverse' }}>{this.defineButton()}</div>
            </Col>,
          );
          break;
        case 1: // 元素占位为1、5、9...
        case 2: // 元素占位为2、6、10...
        case 3: // 元素占位3、7、11...
          // 按钮不用另起一行，直接放在下一个占位区，靠右排放
          children.push(
            <Col span={6} key={new Date().getTime() + Math.random()}>
              <div style={{ width: (22 / 24) * 100 + '%', display: 'flex', flexDirection: 'row-reverse' }}>{this.defineButton()}</div>
            </Col>,
          );
          break;
      }
    }
    if (numInRow === 3) {
      switch ((placeholder - 1) % 3) {
        case 0: // 元素占位为3、6、9...
          children.push(
            <Col span={24} key={new Date().getTime() + Math.random()}>
              <div style={{ width: (70 / 72) * 100 + '%', display: 'flex', flexDirection: 'row-reverse' }}>{this.defineButton()}</div>
            </Col>,
          );
          break;
        case 1: // 元素占位为1、4、7...
        case 2: // 元素占位为2、5、8...
          children.push(
            <Col span={8} key={new Date().getTime() + Math.random()}>
              <div style={{ width: (22 / 24) * 100 + '%', display: 'flex', flexDirection: 'row-reverse' }}>{this.defineButton()}</div>
            </Col>,
          );
          break;
      }
    }
    if (numInRow == 2) {
      switch ((placeholder - 1) % 2) {
        case 0: // 元素占位为2、4、6...
          children.push(
            <Col span={24} key={new Date().getTime() + Math.random()}>
              <div style={{ width: (70 / 72) * 100 + '%', display: 'flex', flexDirection: 'row-reverse' }}>{this.defineButton()}</div>
            </Col>,
          );
          break;
        case 1: // 元素占位为1、3、5...
          children.push(
            <Col span={12} key={new Date().getTime() + Math.random()}>
              <div style={{ width: (22 / 24) * 100 + '%', display: 'flex', flexDirection: 'row-reverse' }}>{this.defineButton()}</div>
            </Col>,
          );
          break;
      }
    }

    return children;
  }

  // 生成查询条件，一行为四个
  getFields4() {
    return this.getFields(4);
  }

  // 生成查询条件，一行为三个
  getFields3() {
    return this.getFields(3);
  }

  getFields2() {
    return this.getFields(2);
  }

  // 定义操作按钮
  defineButton = () => {
    const { allowQuery, allowClear, queryDisabled, buttonText, selfButt } = this.props;
    return (
      <Form.Item>
        {allowQuery && <PrimaryC htmlType='submit' disabled={queryDisabled} title={buttonText} />}
        {allowClear && <PrimaryGhostC title='重置' style={{ marginLeft: '16px', borderRadius: '2px' }} onClick={this.handleReset} />}
        {selfButt}
      </Form.Item>
    );
  };

  // “查询”按钮，抛出查询条件
  handleSearch = (e) => {
    e.preventDefault();
    this.props.form.validateFields((err, values) => {
      // onQuery事件抛出的结果是否包含未设置的,当不包含时，需要将空值删除
      if (!this.props.resultIncludeNull) {
        // 删除用户未设置的条件
        const removeKeys = []; // 保存要删除的条件key值
        Object.getOwnPropertyNames(values).forEach((key) => {
          const value = values[key];
          if (value === undefined || value === null || value === '' || (Array.isArray(value) && value.length == 0)) {
            removeKeys.push(key); // 找出未设置的条件
          }
        });
        // 删除空条件
        for (let i = 0; i < removeKeys.length; i++) {
          delete values[removeKeys[i]];
        }
      }

      // 遍历数组，找出需要特出处理查询条件的组件
      this.props.dataSource.forEach((item, index) => {
        // 证券代码类型的组件
        if (item.type === DATA_ENTRY.SECURITIESCODE && !item.hide) {
          // 若证券代码的值不为空，则从中解析出交易市场和证券代码(证券代码选中后，返回的value的格式是marketCode-securityCode)
          let securitiesValue = values[item.dataIndex];
          if (securitiesValue) {
            if (securitiesValue.indexOf('-') < 0) {
              values[item.dataIndex] = securitiesValue;
            } else {
              values.exchangeCode = securitiesValue.split('-')[0];
              values[item.dataIndex] = securitiesValue.substr(securitiesValue.indexOf('-') + 1).trim(); //取第一个- 后面的数据
            }
          }
        }
        // 精确查询组件
        if (item.type === DATA_ENTRY.SEARCHANDSELECTC && !item.hide) {
          let searchValue = values[item.dataIndex];
          // 精准查询和模糊查询组件抛出查询参数
          if (searchValue) {
            values = { ...values, ...this.state.query };
          }
          delete values[item.dataIndex];
        }
      });
      this.props.onQuery(values); // 抛出查询条件
    });
  };

  // “重置”按钮
  handleReset = () => {
    this.props.form.resetFields(); // 重置条件

    // 遍历数组，将数据转换成可展示的html
    // this.props.dataSource.forEach((item, index) => {
    //   switch (item.type) {
    //     case DATA_ENTRY.RANGEDATE:   // 当组件类型为RANGEDATE，重置需特殊处理
    //       let itemIndex = item.dataIndex.join('_');
    //       this[itemIndex] && this[itemIndex].reset();
    //       item.self && item.self.reset();
    //       break;
    //     case DATA_ENTRY.COMPLEXDATE:
    //       let complexDateIndex = item.startIndex + '_' + item.endIndex;
    //       this[complexDateIndex] && this[complexDateIndex].reset();
    //       item.self && item.self.reset();
    //       break;
    //     case DATA_ENTRY.HOlDDATERANGEC:
    //       let holdDateRangeCIndex = item.startIndex + '_' + item.endIndex;
    //       this[holdDateRangeCIndex] && this[holdDateRangeCIndex].reset();
    //       item.self && item.self.reset();
    //       break;
    //   }
    // });

    this.props.onClear(); // 抛出点击“重置”按钮事件
  };

  render() {
    return (
      <Form id={this.props.parentId} className={style.query} onSubmit={this.handleSearch}>
        <Row justify='space-around'>{this.state.fieldInRow == 4 ? this.getFields4() : this.state.fieldInRow == 3 ? this.getFields3() : this.getFields2()}</Row>
      </Form>
    );
  }
}

// props类型
AdvancedSearch.propsTypes = {
  allowQuery: PropTypes.bool, // 设置是否展示“查询”按钮
  allowClear: PropTypes.bool, // 设置是否展示“重置”按钮
  dataSource: PropTypes.array, // 查询条件数据源
  onQuery: PropTypes.func, // 点击“查询”时，向外抛出查询数据
  onClear: PropTypes.func, // 点击“重置”时，抛出事件
  resultIncludeNull: PropTypes.bool, // 设置onQuery事件抛出的结果是否包含未设置的
  queryDisabled: PropTypes.bool, // 设置查询按钮的失效状态
  buttonText: PropTypes.string, // 按钮文本
  selfButt: PropTypes.object, // 自定义按钮
  onRef: PropTypes.func, // 本组件的引用
  parentId: PropTypes.string, // 非必填项，当该组件不按照自适应的页面分辨率进行展示时，需要设置组件的父节点ID（每个引用需要设置不一样的Id），根据父节点的宽度进行布局设置
};

export default Form.create()(AdvancedSearch);
